﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Intorise.Common;
using System.Threading;
using System.Net;
using Intorise.Net;
using System.Net.Sockets;
using System.Drawing;
using Config;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using System.IO;
using System.Configuration;

namespace Model
{
    public class BotEngine
    {
        static readonly string LOGIN_SERVER_URL = ConfigurationManager.AppSettings["LOGIN_SERVER_URL"];
        #region login object
        protected byte[] head = new byte[] { 0x00, 0x01, 0x87, 0x70 };
        protected byte[] serverNo = null;
        protected byte[] accountData = null;
        protected byte[] time = null;
        protected byte[] singn = null;
        protected string ip = null;
        protected int port = 0;
        #endregion

        #region AutoResetEvent
        protected AutoResetEvent loginResetEvent = new AutoResetEvent(false);
        #endregion

        bool quit = false;
        protected Player player = null;
        protected NetTools net = new NetTools(60);
        Dictionary<MessageTypeEnum, Processor> processorDict = new Dictionary<MessageTypeEnum, Processor>();
        List<Message> messages = new List<Message>();
        List<Monster> monsters = new List<Monster>();
        Thread messageReadThread = null;
        Thread messageProcessThread = null;
        Thread monsterProcessThread = null;
        object messageLocker = new object();
        object monsterLocker = new object();
        bool engineRunning = false;
        protected bool infoLog = false;
        protected bool changeIP = false;
        protected Adsl adsl = new Adsl();
        protected TcpClient Client { get; set; }
        public bool Initialized { get; set; }
        byte flagA, flagB;
        bool cantLogin = false;

        public BotEngine(Player player)
        {
            this.player = player;
            infoLog = ((MainConfig)ConfigManager.ApplicationConfig).LogServerInfo;
            changeIP = ((MainConfig)ConfigManager.ApplicationConfig).ValidateCodeReconnect;
            InitProcessor();
        }

        public void RegisterProcessor(Processor processor)
        {
            if (processorDict.ContainsKey(processor.MessageType))
            {
                return;
            }
            processorDict.Add(processor.MessageType, processor);
        }

        public virtual bool RemoteLogin()
        {

            string loginUrl = string.Format(LOGIN_SERVER_URL, player.AccountName, player.PlayerAccount.Password, player.ServerID);

            ConsoleBLL.WriteLine(player + " 开始登录...");

            LoginEntity loginEntity = null;
            DateTime begin = DateTime.Now;
            HttpWebRequest request = null;
            HttpWebResponse response = null;
            var html = "";

            while (true)
            {
                request = net.SendRequest(loginUrl, "GET");
                response = (HttpWebResponse)request.GetResponse();
                html = net.GetResponseHtml(response);
                response.Close();

                loginEntity = JsonConvert.DeserializeObject<LoginEntity>(html);
                if (infoLog)
                {
                    ConsoleBLL.WriteLineInfo(player + " login result:" + html);
                }

                if (loginEntity.LoginStatus == LoginStatusEnum.Completed)
                {
                    break;
                }
                if ((DateTime.Now - begin).TotalMinutes > 1)
                {
                    ConsoleBLL.WriteLineInfo("登录超时");
                    break;
                }//超过1分钟退出循环
                Thread.Sleep(2000);
            }

            if (loginEntity.LoginResult != LoginResultEnum.Success)
            {
                switch (loginEntity.LoginResult)
                {
                    case LoginResultEnum.TryTooManyTimes:
                    case LoginResultEnum.WrongPassword:
                    case LoginResultEnum.UnkowError:
                    case LoginResultEnum.Banned:
                        ConsoleBLL.WriteLineError(player + " 登录失败：" + loginEntity.LoginResult + " 停止登录");
                        player.Status = PlayerStatusEnum.停止;
                        break;
                    default:
                        ConsoleBLL.WriteLineError(player + " 登录失败：登录服务器返回登录失败！");
                        player.Status = PlayerStatusEnum.等待;
                        break;
                }
                return false;
            }

            player.Cookie = new CookieContainer();
            loginEntity.Cookies.ForEach(x =>
            {
                player.Cookie.Add(
                    new Cookie
                    {
                        Domain = x.Domain,
                        Name = x.Name,
                        Value = x.Value,
                        Expires = x.Expires,
                        Expired = x.Expired,
                        Path = x.Path,
                    }
                );
            });

            //string enterGameUrl = "http://gameapp.37.com/controller/enter_game.php?game_id=237&sid={0}&showlogintype=1&refer=37wancom";
            //request = net.SendRequest(string.Format(enterGameUrl, player.ServerID), "GET", player.Cookie);

            //response = (HttpWebResponse)request.GetResponse();
            //html = net.GetResponseHtmlGzip(response);
            //response.Close();
            //var registerServerUrl = response.Headers["location"];

            //if (registerServerUrl == null || html.Contains("验证码"))
            //{
            //    ConsoleBLL.WriteLineError(player + " 登录失败：进入游戏地址为空或出现验证码！");
            //    return false;
            //}
            //request = net.SendRequest(registerServerUrl, "GET", player.Cookie);
            //response = (HttpWebResponse)request.GetResponse();
            //html = net.GetResponseHtmlGzip(response);
            //response.Close();

            //port = GameHelper.GetPort(html);
            //if (port == 0)
            //{
            //    ConsoleBLL.WriteLineError(player + " 登录失败：无法获取服务器端口，html:");
            //    ConsoleBLL.WriteLine(html);
            //    return false;
            //}

            head = new byte[] { 0x00, 0x01, 0x87, 0x70 };
            serverNo = Tools.GetAscII(player.PlayerAccount.ServerID);
            accountData = Tools.GetAscII(player.PlayerAccount.Username);
            //time = Tools.GetAscII(GameHelper.GetTime(html));
            //singn = Tools.GetAscII(GameHelper.GetSign(html));
            //ip = GameHelper.GetIP(html);
            time = Tools.GetAscII(loginEntity.TicketTime);
            singn = Tools.GetAscII(loginEntity.Sign);
            ip = loginEntity.ServerIP;
            port = loginEntity.Port;
            return true;
        }

        public virtual bool LocalLogin()
        {
            //string loginUrl = string.Format(LOGIN_SERVER_URL, player.AccountName, player.PlayerAccount.Password, player.ServerID);
            string loginUrl = "https://my.37.com/api/login.php?action=login&login_account={0}&password={1}&ajax=0&remember_me=1&save_state=0&ltype=1&s=1";
            string enterGameUrl = "http://gameapp.37.com/controller/enter_game.php?game_id=237&sid={0}&showlogintype=1&refer=37wancom";
            //string registerUrl = "http://api.dts.37wan.com/client/?user_name={0}&is_adult=1&sign={1}&server_id=S{2}&client=1&channel=0&real_user=1&user_info=1&tg_pass=0&time={3}";
            string registerServerUrl = null;

        BeginLogin:
            var cookies = new CookieContainer();
            ConsoleBLL.WriteLine(player + " 开始登录...");

            string codeData = "";

            var request = net.SendRequest(string.Format(loginUrl, player.PlayerAccount.Username, Encrypt(player.PlayerAccount.Password)) + codeData, "GET", cookies);
            var response = (HttpWebResponse)request.GetResponse();
            var html = net.GetResponseHtmlGzip(response).Replace("callback(", "").Replace(")", "");
            response.Close();
            JObject result = (JObject)JsonConvert.DeserializeObject(html);

            var flag = result["code"].ToString();
            switch (flag)
            {
                case "-7":
                case "-11":
                    ConsoleBLL.WriteLineError(player + " 出现验证码");
                    adsl.ConnectAndCheckIP();
                    return false;
                case "-2":
                    ConsoleBLL.WriteLineError(player + " 登录失败，密码错误");
                    ConsoleBLL.WriteLine(html.ToString());
                    this.player.Status = PlayerStatusEnum.账户密码错误;
                    return false;
                case "-1":
                    ConsoleBLL.WriteLineError(player + " 登录失败，账户名错误");
                    ConsoleBLL.WriteLine(html.ToString());
                    this.player.Status = PlayerStatusEnum.账户密码错误;
                    return false;
                case "-10":
                    ConsoleBLL.WriteLineError(player + " 登录尝试次数过多");
                    ConsoleBLL.WriteLine(html.ToString());
                    this.player.Status = PlayerStatusEnum.停止;
                    return false;
            }

        GetRegisterServerUrl:
            request = net.SendRequest(string.Format(enterGameUrl, player.ServerID), "GET", cookies);

            response = (HttpWebResponse)request.GetResponse();
            html = net.GetResponseHtmlGzip(response);
            response.Close();
            registerServerUrl = response.Headers["location"];

            if (registerServerUrl == null || html.Contains("验证码"))
            {
            InputCode:
                bool success = false;
                if (html.Contains("验证码"))
                {
                    success = InputCode(cookies);
                }
                else
                {
                    ConsoleBLL.WriteLineError(player + " 无法获取服务地址，html:");
                    adsl.ConnectAndCheckIP();
                    return false;
                }
                if (success)
                {
                    goto GetRegisterServerUrl;
                }
                else
                {
                    goto InputCode;
                }
            }

            #region 获取cookie
            request = net.SendRequest("https://my.37.com/httpsEnable.gif?t=1449296460816", "GET", cookies);
            response = (HttpWebResponse)request.GetResponse();
            response.Close();
            request = net.SendRequest("http://cm.he2d.com/1/", "GET", cookies);
            response = (HttpWebResponse)request.GetResponse();
            response.Close();

            request = net.SendRequest("http://my.37.com/api/message_api.php?action=is_remind&callback=aaa&_=1449297015903", "GET", cookies);
            response = (HttpWebResponse)request.GetResponse();
            response.Close();
            #endregion

            request = net.SendRequest(registerServerUrl, "GET", cookies);
            response = (HttpWebResponse)request.GetResponse();
            html = net.GetResponseHtmlGzip(response);

            port = GameHelper.GetPort(html);
            if (port == 0)
            {
                ConsoleBLL.WriteLineError(player + " 无法获取服务器端口，html:");
                ConsoleBLL.WriteLine(html);
                return false;
            }

            head = new byte[] { 0x00, 0x01, 0x87, 0x70 };
            serverNo = Tools.GetAscII(player.PlayerAccount.ServerID);
            accountData = Tools.GetAscII(player.PlayerAccount.Username);
            time = Tools.GetAscII(GameHelper.GetTime(html));
            singn = Tools.GetAscII(GameHelper.GetSign(html));
            ip = GameHelper.GetIP(html);

            return true;
        }

        public virtual bool EnterGameServer()
        {

            Client = new TcpClient(ip, 843);
            var data = Tools.GetAscII("<policy-file-request/>\0");
            net.SendData(Client, data);
            Client.Close();

            Client = new TcpClient(ip, port);
            Begin();

            data = Tools.Contact(head, DataPackager.GetNetworkData((short)serverNo.Length), serverNo, net.GetNetworkBytes((short)player.PlayerAccount.Username.Length), accountData, new byte[] { 0x00, 0x00, 0x00, 0x00, 0x00, 0x0A }
                , time, new byte[] { 0x00, 0x01, 0x33, 0x00, 0x20 }, singn
                , new byte[] { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x35, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x30, 0x00, 0x01, 0x31, 0x00, 0x01, 0x30 });
            data = Tools.Contact(net.GetNetworkBytes(data.Length), data);
            net.SendData(Client, data, data.Length);

            //byte[] buffer = new byte[10240];
            //var stream = Client.GetStream();
            //int size = stream.Read(buffer, 0, buffer.Length);//读取 00 00 00 05 00 03 0D A5 00

            //size = stream.Read(buffer, 0, buffer.Length);

            //ConsoleBLL.WriteLineWaring(Tools.GetHexString(buffer, size));


            DateTime startTime = DateTime.Now;
            while (!player.Entered)
            {
                Thread.Sleep(500);
                if (player.Config.TimeoutLogin < (DateTime.Now - startTime).TotalSeconds) { break; }
            }

            if (!player.Entered)
            {
                ConsoleBLL.WriteLineWaring(player + " 进入游戏超时！");
                string loginUrl = string.Format(LOGIN_SERVER_URL, player.AccountName, player.PlayerAccount.Password, player.ServerID) + "&remove=true";

                ConsoleBLL.WriteLine(player + " 删除已登录账号...");
                HttpWebRequest request = net.SendRequest(loginUrl, "GET");
                HttpWebResponse response = (HttpWebResponse)request.GetResponse();
                var html = net.GetResponseHtml(response);
                response.Close();

                Stop();
            }
            return player.Entered;
        }

        public virtual bool CreateCharacter()
        {
            loginResetEvent.Reset();
            Client = new TcpClient(ip, 843);
            var data = Tools.GetAscII("<policy-file-request/>\0");
            net.SendData(Client, data);
            Client.Close();

            Client = new TcpClient(ip, port);

            GameHelper.RunThread(() =>
            {
                try
                {
                    data = Tools.Contact(head, DataPackager.GetNetworkData((short)serverNo.Length), serverNo, net.GetNetworkBytes((short)player.PlayerAccount.Username.Length), accountData, new byte[] { 0x00, 0x00, 0x00, 0x00, 0x00, 0x0A }
                        , time, new byte[] { 0x00, 0x01, 0x33, 0x00, 0x20 }, singn
                        , new byte[] { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x35, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x30, 0x00, 0x01, 0x31, 0x00, 0x01, 0x30 });
                    data = Tools.Contact(net.GetNetworkBytes(data.Length), data);
                    net.SendData(Client, data, data.Length);
                    byte[] buffer = new byte[10240];
                    var stream = Client.GetStream();
                    int size = stream.Read(buffer, 0, buffer.Length);
                    ConsoleBLL.WriteLineWaring(Tools.GetHexString(buffer, size));

                    size = stream.Read(buffer, 0, buffer.Length);
                    ConsoleBLL.WriteLineWaring(Tools.GetHexString(buffer, size));

                    SendData(new byte[] { 0x00, 0x00, 0x00, 0x05, 0x00, 0x01, 0x87, 0x6E, 0x00 });
                    Thread.Sleep(100);
                    size = stream.Read(buffer, 0, buffer.Length);
                    ConsoleBLL.WriteLineWaring(Tools.GetHexString(buffer, size));

                    string name = GameHelper.GetRandomName();
                    data = DataPackager.GetCreateCharacterData(name);
                    SendData(data);
                    Thread.Sleep(100);
                    size = stream.Read(buffer, 0, buffer.Length);
                    ConsoleBLL.WriteLineWaring(Tools.GetHexString(buffer, size));
                    //SendData(new byte[] { 0x00, 0x00, 0x00, 0x0D, 0x00, 0x01, 0x87, 0x6C, 0x00, 0x00, 0x00, 0x07, 0x80, 0x00, 0x00, 0x03, 0xEA });
                    //Thread.Sleep(100);
                    size = stream.Read(buffer, 0, buffer.Length);
                    ConsoleBLL.WriteLineWaring(Tools.GetHexString(buffer, size));
                    if (size > 9)
                    {
                        player.Status = PlayerStatusEnum.角色已创建;
                        player.Name = name;
                    }
                    Client.Close();
                }
                catch (Exception ex)
                {
                    //ConsoleBLL.WriteLineWaring("出错：" + ex.Message);
                }
                finally
                {
                    loginResetEvent.Set();
                }
            });
            var result = loginResetEvent.WaitOne(player.Config.TimeoutLogin * 1000);
            return true;
        }

        public void Begin()
        {
            engineRunning = true;
            quit = false;
            BeginMessageRead();
            BeginMessageDispatch();
            BeginProcessMonster();
        }

        public void BeginMessageRead()
        {
            messageReadThread = new Thread(new ParameterizedThreadStart(x =>
            {
                try
                {
                    var stream = Client.GetStream();
                    int length = 0;
                    byte[] buffer = new byte[102400];
                    while (!quit)
                    {
                        try
                        {
                            if (!stream.DataAvailable) { Thread.Sleep(100); continue; }
                            length = stream.Read(buffer, 0, 4);//读取4个字节为接下来的数据包的长度
                            if (length < 4)
                            {
                                continue;
                            }
                            var packgetLength = net.GetHostInt32(buffer, 0);

                            if (packgetLength >= 0x1000000)
                            {
                                packgetLength = packgetLength - 0x1000000;
                                if (packgetLength > buffer.Length)
                                {
                                    //buffer = new byte[packgetLength];
                                    continue;
                                }

                                length = stream.Read(buffer, 0, packgetLength);
                                //ConsoleBLL.WriteLine("packgetLength：" + packgetLength+"，read length："+length);
                                MemoryStream output = new MemoryStream(length);
                                zlib.ZOutputStream outZStream = new zlib.ZOutputStream(output);

                                outZStream.Write(buffer, 4, length - 4);//从第4个开始解压数据
                                outZStream.Flush();

                                var datas = output.ToArray();//datas里就是解压过后的数据
                                if (datas.Length + 4 > buffer.Length)
                                {
                                    continue;//超过100k的数据跳过
                                }
                                Array.Copy(datas, 0, buffer, 4, datas.Length);//在把解压过后的数据复制回去
                                length = datas.Length + 4;
                            }
                            else
                            {
                                if (packgetLength > buffer.Length)
                                {
                                    //buffer = new byte[packgetLength]; 
                                    continue;
                                }
                                length = stream.Read(buffer, 0, packgetLength);
                            }

                            Message msg = DataPackager.GetMessage(buffer.Take(length).ToArray());

                            messages.Add(msg);
                        }
                        catch (Exception ex)
                        {
                            if (ex is ThreadAbortException)
                            {
                            }
                            else
                            {
                                ConsoleBLL.WriteLineError("接收消息失败：\r\n" + ex.Message + "\r\n" + ex.StackTrace);
                            }

                        }
                    }
                    ConsoleBLL.WriteLineError(player + " 消息接收已退出！");
                }
                catch
                {
                }
            }),1024);
            messageReadThread.IsBackground = true;
            messageReadThread.Start();
        }

        public void BeginMessageDispatch()
        {
            messageProcessThread = new Thread(new ParameterizedThreadStart(x =>
            {
                while (!quit)
                {
                    if (messages.Count == 0)
                    {
                        Thread.Sleep(100);
                        continue;
                    }
                    try
                    {
                        lock (messageLocker)
                        {
                            for (int i = 0; i < messages.Count; i++)
                            {
                                if (quit) { break; }
                                if (messages[i] == null)
                                {
                                    ConsoleBLL.WriteLineError("消息为null，索引：" + i);
                                    continue;
                                }

                                if (!processorDict.ContainsKey(messages[i].MessageType))
                                {
                                    if (((MainConfig)ConfigManager.ApplicationConfig).LogDebugInfo)
                                    {
                                        ConsoleBLL.WriteLineWaring("未处理的消息，编号：" + messages[i].Type.ToString("X2") + "，长度：" + messages[i].Length);
                                        ConsoleBLL.WriteLineWaring(Tools.GetHexString(messages[i].Data, messages[i].Data.Length));
                                        ConsoleBLL.WriteLineInfo(Tools.ConvertChar(Tools.GetString(messages[i].Data)));
                                    }
                                    continue;
                                }
                                try
                                {
                                    processorDict[messages[i].MessageType].Process(messages[i]);
                                }
                                catch (Exception ex)
                                {
                                    GameHelper.Handle(ex);
                                }
                                //if (processorDict[messages[i].MessageType].RemoveWhenProcessed)
                                //{
                                //    processorDict.Remove(messages[i].MessageType);
                                //}
                            }
                            messages.Clear();
                        }
                    }
                    catch (Exception ex)
                    {
                        GameHelper.Handle(ex);
                    }
                }
                ConsoleBLL.WriteLineInfo("消息处理已退出");
            }),1024);
            messageProcessThread.IsBackground = true;
            messageProcessThread.Start();
        }

        public void BeginProcessMonster()
        {
            monsterProcessThread = new Thread(new ParameterizedThreadStart(x =>
            {
                while (!quit)
                {
                    try
                    {
                        lock (monsterLocker)
                        {
                            for (int i = 0; i < monsters.Count; i++)
                            {
                                if (quit) { break; }
                                if (!monsters[i].Alive || GameHelper.GetDistance(player.Location, monsters[i].Location) > player.Config.RemoveMonsterDistance)//死亡的或者超过距离的移除
                                {
                                    //ConsoleBLL.WriteLine("怪物" + i + "已被移除");
                                    monsters.RemoveAt(i--);
                                }
                                //Thread.Sleep(10);
                            }
                        }
                    }
                    catch (Exception ex)
                    {
                        GameHelper.Handle(ex);
                    }
                    Thread.Sleep(200);
                }
            }),1024);
            monsterProcessThread.IsBackground = true;
            monsterProcessThread.Start();
        }

        public void Stop()
        {
            if (!engineRunning) { return; }
            engineRunning = false;
            quit = true;

            try
            {
                Client.Close();
            }
            catch (Exception ex) { }

            try
            {
                messageReadThread.Abort();
            }
            catch (Exception ex) { }

            try
            {
                messageProcessThread.Abort();
            }
            catch (Exception ex) { }

            try
            {
                monsterProcessThread.Abort();
            }
            catch (Exception ex) { }
            ConsoleBLL.WriteLineInfo(this.player + "消息处理引擎已停止");
        }

        /// <summary>
        /// 发现怪物
        /// </summary>
        /// <param name="monster"></param>
        public void Found(Monster monster)
        {
            try
            {
                lock (monsterLocker)
                {
                    if (monsters.Count(x => x.InstanceID == monster.InstanceID) == 0)
                    {
                        if (monsters.Count(x => x.InstanceID == monster.InstanceID) == 0)
                        {
                            monster.Distance = GameHelper.GetDistance(player.Location, monster.Location);
                            monsters.Add(monster);
                        }
                    }
                }
            }
            catch (Exception ex)
            {
                GameHelper.Handle(ex);
            }
        }

        public void RefreshMonsterLocation(long id, Point location)
        {
            try
            {
                lock (monsterLocker)
                {
                    var monster = monsters.Where(x => x.InstanceID == id).FirstOrDefault();

                    if (monster == null)//没找到则增加
                    {
                        Found(new Monster { Name = "未知怪物", InstanceID = id, Location = location });
                    }
                    else
                    {
                        monster.Location = location;
                        monster.Distance = GameHelper.GetDistance(player.Location, monster.Location);
                    }
                }
            }
            catch (Exception ex)
            {
                GameHelper.Handle(ex);
            }
        }

        /// <summary>
        /// 获取最近的怪物
        /// </summary>
        /// <returns></returns>
        public Monster GetOneNearestMonster(string name = null)
        {
            Monster m = null;
            double distance = double.MaxValue;
            try
            {
                lock (monsterLocker)
                {
                    if (monsters.Count == 0) { return null; }
                    foreach (var monster in monsters)
                    {
                        if (name != null && name != monster.Name) { continue; }
                        double j = GameHelper.GetDistance(player.Location, monster.Location);
                        if (j < distance)
                        {
                            m = monster;
                        }
                    }
                }
            }
            catch (Exception ex)
            {
                GameHelper.Handle(ex);
            }
            return m;
        }

        public List<Monster> GetNearestMonster(int count = 6)
        {
            List<Monster> list = new List<Monster>(0);
            try
            {
                lock (monsterLocker)
                {
                    if (monsters.Count == 0) { return list; }
                    list = monsters.Where(x => x.Alive).OrderBy(x => x.Distance).Take(count).ToList();
                }
            }
            catch (Exception ex)
            {
                GameHelper.Handle(ex);
            }
            return list;
        }

        public void SendData(byte[] data)
        {
            try
            {
                if (Client.Connected)
                {
                    net.SendData(Client, data);
                }
            }
            catch (Exception ex)
            {
                //ConsoleBLL.WriteLineError(this+" 发送数据失败！\r\n" + ex.Message + "\r\n" + ex.StackTrace);
                ConsoleBLL.WriteLineError(this.player+" 连接已被中断");
                Stop();
                throw new Exception("已断线");
            }
        }

        public void InitProcessor()
        {
            Initialized = true;
            RegisterProcessor(new Processor("登录处理器", MessageTypeEnum.LoginSuccess, ProcessLogin));
            RegisterProcessor(new Processor("登录处理器1", MessageTypeEnum.LoginSuccess1, ProcessLogin1));
            // RegisterProcessor(new Processor("查看等级", MessageTypeEnum.ViewLevel, ProcessViewLevel));
            RegisterProcessor(new Processor("地图切换处理器", MessageTypeEnum.CurrentMap, ProcessCurrentMap));
            RegisterProcessor(new Processor("地图传送处理器", MessageTypeEnum.TransmitMap, ProcessTransmitMap));
            RegisterProcessor(new Processor("怪物刷新处理器", MessageTypeEnum.MonsterRefreshed, ProcessMonsterRefresh));
            RegisterProcessor(new Processor("ProcessMonsterFonded", MessageTypeEnum.MonsterFounded, ProcessMonsterFonded));
            RegisterProcessor(new Processor("ProcessMonsterMoved", MessageTypeEnum.MonsterMoved, ProcessMonsterMoved));
        }
        bool Create = false;

        public bool ProcessLogin(Message msg)
        {
            //if (msg.Data.Length == 8)//没有建立角色
            //{
            //    player.CreateCharacter();
            //}
            try
            {
                var message = new LoginSuccessMsg(msg.Data);
                player.ID = message.ID;
                if (player.ID == 0) { return false; }
                player.Name = message.Name;
                player.Level = message.Level;
                player.Version = message.Version;
                ConsoleBLL.WriteLine(string.Format("{0}进入游戏成功，角色名：{1}，当前等级：{2}", player.PlayerAccount.Username, player.Name, player.Level));

                var datas = new byte[] { 0x00, 0x00, 0x00, 0x0e, 0x00, 0x01, 0x87, 0x6A };
                datas = Tools.Contact(datas, net.GetNetworkBytes(player.ID), player.Version);
                net.SendData(Client, datas);
                datas = new byte[] { 0x00, 0x00, 0x00, 0x05, 0x00, 0x01, 0x87, 0x6E, 0x00 };
                net.SendData(Client, datas);
                Thread.Sleep(500);

                //datas = new byte[] { 0x00, 0x00, 0x00, 0x09, 0x00, 0x01, 0x87, 0x6C, 0x00, 0x80, 0x1e, 0xd4, 0x0f };
                datas = new byte[] { 0x00, 0x00, 0x00, 0x09, 0x00, 0x01, 0x87, 0x6C, 0x00, 0xC0, 0x16, 0x80, 0x0D };
                net.SendData(Client, datas);
                Thread.Sleep(500);

                datas = new byte[] { 0x00, 0x00, 0x00, 0x05, 0x00, 0x01, 0xD9, 0x72, 0x00 };
                net.SendData(Client, datas);

                datas = Tools.Contact(new byte[] { 0x00, 0x02, 0x17, 0x8E }, DataPackager.GetNetworkData((short)accountData.Length), accountData, DataPackager.GetNetworkData(player.ID), player.Version, new byte[] { 0x00, 0x02, 0x2D, 0x31 });
                datas = Tools.Contact(net.GetNetworkBytes(datas.Length), datas);
                net.SendData(Client, datas);

                datas = new byte[] { 0x00, 0x00, 0x00, 0x05, 0x00, 0x07, 0xC8, 0xFA, 0x00 };
                net.SendData(Client, datas);
                datas = new byte[] { 0x00, 0x00, 0x00, 0x05, 0x00, 0x07, 0xC8, 0xFA, 0x02 };
                net.SendData(Client, datas);

                datas = new byte[] { 0x00, 0x00, 0x00, 0x07, 0x00, 0x01, 0xF4, 0xD5, 0xDA, 0x8C, 0x01 };
                net.SendData(Client, datas);

                datas = new byte[] { 0x00, 0x00, 0x00, 0x05, 0x00, 0x07, 0xbe, 0xed, 0x0c };
                net.SendData(Client, datas);

                datas = new byte[] { 0x00, 0x00, 0x00, 0x05, 0x00, 0x09, 0x28, 0x99, 0x02 };
                net.SendData(Client, datas);

                datas = new byte[] { 0x00, 0x00, 0x00, 0x06, 0x00, 0x07, 0xCC, 0xE1, 0x98, 0x01 };
                net.SendData(Client, datas);

                datas = new byte[] { 0x00, 0x00, 0x00, 0x04, 0x00, 0x02, 0x00, 0x88 };
                net.SendData(Client, datas);

                datas = new byte[] { 0x00, 0x00, 0x00, 0x05, 0x00, 0x08, 0x2A, 0xA4, 0x00 };
                net.SendData(Client, datas);

                datas = new byte[] { 0x00, 0x00, 0x00, 0x04, 0x00, 0x01, 0x8B, 0x5B };
                net.SendData(Client, datas);

                //datas = new byte[] { 0x00, 0x00, 0x00, 0x05, 0x00, 0x08, 0x13, 0x3A,0x00 };
                //net.SendData(Client, datas);

                datas = new byte[] { 0x00, 0x00, 0x00, 0x05, 0x00, 0x02, 0x33, 0x4A, 0x01 };
                net.SendData(Client, datas);

                datas = new byte[] { 0x00, 0x00, 0x00, 0x04, 0x00, 0x08, 0x2A, 0xB3 };
                net.SendData(Client, datas);
                Thread.Sleep(500);

                //datas = new byte[] { 0x00, 0x00, 0x00, 0x04, 0x00, 0x08, 0x0F, 0xCA };
                //net.SendData(Client, datas);

                //datas = new byte[] { 0x00, 0x00, 0x00, 0x04, 0x00, 0x01, 0x8B, 0x5B };
                //net.SendData(Client, datas);

                datas = new byte[] { 0x00, 0x00, 0x00, 0x37, 0x00, 0x01, 0xD5, 0x99, 0x00, 0x30, 0x00, 0x00, 0x04, 0x00, 0x00, 0x04, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x02, 0x00, 0x00, 0x00, 0x82, 0x02, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
                net.SendData(Client, datas);

                datas = new byte[] { 0x00, 0x00, 0x00, 0x04, 0x00, 0x08, 0x0f, 0xca };
                net.SendData(Client, datas);
                Thread.Sleep(500);

                datas = new byte[] { 0x00, 0x00, 0x00, 0x04, 0x00, 0x01, 0x8B, 0x5B };
                net.SendData(Client, datas);

                datas = new byte[] { 0x00, 0x00, 0x00, 0x37, 0x00, 0x01, 0xD5, 0x99, 0x00, 0x30, 0x00, 0x00, 0x04, 0x00, 0x00, 0x04, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x02, 0x00, 0x00, 0x00, 0x82, 0x02, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
                net.SendData(Client, datas);

                player.Entered = true;
            }
            catch (Exception ex)
            {
                GameHelper.Handle(ex);
                return false;
            }
            finally
            {
                //loginResetEvent.Set();
            }
            return true;
        }

        public bool ProcessViewLevel(Message msg)
        {
            try
            {
                var message = new ProcessViewLevelMsg(msg.Data);
                player.Level = message.Level;
                player.Entered = true;

            }
            catch
            {
                return false;
            }
            return true;
        }

        public bool ProcessLogin1(Message msg)
        {
            try
            {
                if (Create == false)
                    return true;
                var message = new LoginSuccessMsg1(msg.Data);
                var datas = new byte[] { 0x00, 0x00, 0x00, 0x05 };


                player.ID = message.ID;
                player.Name = message.Name;
                player.Level = 1;
                player.Version = message.Version;
                ConsoleBLL.WriteLine(string.Format("{0}进入游戏成功，角色名：{1}，当前等级：{2}", player.PlayerAccount.Username, player.Name, player.Level));

                datas = new byte[] { 0x00, 0x00, 0x00, 0x0e, 0x00, 0x01, 0x87, 0x6A };
                datas = Tools.Contact(datas, net.GetNetworkBytes(player.ID), player.Version);
                net.SendData(Client, datas);
                datas = new byte[] { 0x00, 0x00, 0x00, 0x05, 0x00, 0x01, 0x87, 0x6E, 0x00 };
                net.SendData(Client, datas);
                datas = new byte[] { 0x00, 0x00, 0x00, 0x09, 0x00, 0x01, 0x87, 0x6C, 0x00, 0x80, 0x1e, 0xd4, 0x0f };
                net.SendData(Client, datas);
                datas = Tools.Contact(new byte[] { 0x00, 0x02, 0x17, 0x8E }, DataPackager.GetNetworkData((short)accountData.Length), accountData, DataPackager.GetNetworkData(player.ID), player.Version, new byte[] { 0x00, 0x02, 0x2D, 0x31 });
                datas = Tools.Contact(net.GetNetworkBytes(datas.Length), datas); net.SendData(Client, datas);
                datas = new byte[] { 0x00, 0x00, 0x00, 0x05, 0x00, 0x07, 0xC8, 0xFA, 0x00 };
                net.SendData(Client, datas);
                datas = new byte[] { 0x00, 0x00, 0x00, 0x05, 0x00, 0x07, 0xC8, 0xFA, 0x02 };
                net.SendData(Client, datas);
                datas = new byte[] { 0x00, 0x00, 0x00, 0x05, 0x00, 0x07, 0xbe, 0xed, 0x0c };
                net.SendData(Client, datas);
                datas = new byte[] { 0x00, 0x00, 0x00, 0x05, 0x00, 0x09, 0x28, 0x99, 0x02 };
                net.SendData(Client, datas);


                datas = new byte[] { 0x00, 0x00, 0x00, 0x05, 0x00, 0x07, 0xCC, 0xE1, 0x3C };
                net.SendData(Client, datas);
                datas = new byte[] { 0x00, 0x00, 0x00, 0x05, 0x00, 0x01, 0xF4, 0xD5, 0x00 };
                net.SendData(Client, datas);
                datas = new byte[] { 0x00, 0x00, 0x00, 0x04, 0x00, 0x02, 0x00, 0x88 };
                net.SendData(Client, datas);
                datas = new byte[] { 0x00, 0x00, 0x00, 0x04, 0x00, 0x01, 0x8B, 0x5B };
                net.SendData(Client, datas);
                datas = new byte[] { 0x00, 0x00, 0x00, 0x04, 0x00, 0x08, 0x13, 0x3A };
                net.SendData(Client, datas);
                datas = new byte[] { };
                net.SendData(Client, datas);

                Create = false;
                player.Entered = true;
            }
            catch (Exception ex)
            {
                GameHelper.Handle(ex);
                return false;
            }
            finally
            {
                //loginResetEvent.Set();
            }
            return true;
        }

        public bool ProcessCurrentMap(Message x)
        {
            //GameHelper.Run(x, r =>
            //{
                var msg = new CurrentMapMsg(x.Data);
                player.CurrentMap = Maps.GetMap(msg.ID);
                ConsoleBLL.WriteLine("(CurrentMap)当前地图：" + player.CurrentMap.Name);
            //});
            return true;
        }

        public bool ProcessTransmitMap(Message x)
        {
            //GameHelper.Run(x, r =>
            //{
                var item = new TransmitMsg(x.Data);
                player.CurrentMap = item.CurrentMap;
                ConsoleBLL.WriteLineInfo("(TransmitMap)当前地图：" + item.CurrentMap.Name);
            //});
            return true;
        }

        public bool ProcessMonsterRefresh(Message x)
        {
            //GameHelper.Run(x, r =>
            //{
                var item = new MonsterRefreshedMsg(x.Data);
                var distance = GameHelper.GetDistance(player.Location, item.Location);
                //ConsoleBLL.WriteLineInfo("怪物刷新：" + item.Name + "(" + item.ID.ToString("X2") + ")，" + item.CurrentMap.Name + "(" + item.Location + ")，距离：" + distance);
                if (distance <= player.Config.RemoveMonsterDistance)
                {
                    Found(new Monster { InstanceID = item.ID, Name = item.Name, Location = item.Location });
                }
            //});
            return true;
        }

        public bool ProcessMonsterFonded(Message x)
        {
            return false;
            GameHelper.Run(x, r =>
            {
                var item = new MonsterFoundedMsg(x.Data);
                //ConsoleBLL.WriteLineInfo("发现怪物：" + item.Name + "(" + item.ID.ToString("X2") + ")，" + item.CurrentMap.Name + "(" + item.Location + ")");
                Found(new Monster { InstanceID = item.ID, Name = item.Name, Location = item.Location });
            });
            return false;
        }

        public bool ProcessMonsterMoved(Message x)
        {
            //GameHelper.Run(x, r =>
            //{
                var item = new MonsterMovedMsg(x.Data);
                //ConsoleBLL.WriteLine(string.Format("怪物{0}移动->{1}", item.MoverID, item.Location));
                RefreshMonsterLocation(item.MoverID, item.Location);
            //});
            return false;
        }

        public bool ProcessPlayerFounded(Message x)
        {
            //GameHelper.Run(x, r =>
            //{
                var item = new PlayerFoundedMsg(x.Data);
                ConsoleBLL.WriteLineInfo(string.Format("发现玩家：{0}({1})，等级：{2}，HP：{3}/{4}，MP：{5}/{6}，坐标：{7}",
                    item.Name, item.ID, item.Length, item.CurrentHP, item.TotalHP, item.CurrentMP, item.TotalMP, item.Location));
            //});
            return true;
        }

        private bool InputCode(CookieContainer cookies)
        {
            //http://gameapp.37.com/controller/code.php
            var request = net.SendRequest("http://gameapp.37.com/controller/code.php", "GET", cookies);
            var data = net.GetResponseData((HttpWebResponse)request.GetResponse(), true);
            Image image = Bitmap.FromStream(new MemoryStream(data));
            //ConsoleBLL.WriteLineWaring("Code:\r\n"+html);
            var code = GameHelper.GetCode(image);
            //					data:{code:code,key:"dts_entergame",action:"check_code"},
            request = net.SendRequest("http://gameapp.37.com/controller/code.php", "POST", cookies);
            net.PostData("code=" + code + "&key=dts_entergame&action=check_code", request);
            var html = net.GetResponseHtmlGzip(request);
            ConsoleBLL.WriteLineWaring("Check Code:\r\n" + html);
            var result = (JObject)JsonConvert.DeserializeObject(html);
            Thread.Sleep(500);
            if (result["code"].ToString() == "1")
            {
                return true;
            }
            else
            {
                ConsoleBLL.WriteLineError(this.player + " 验证码错误！");
            }
            return false;
        }

        private string GetCode(CookieContainer cookies)
        {
            //http://gameapp.37.com/controller/code.php
            var request = net.SendRequest("http://my.37.com/code.php", "GET", cookies);
            var data = net.GetResponseData((HttpWebResponse)request.GetResponse(), true);
            Image image = Bitmap.FromStream(new MemoryStream(data));
            return GameHelper.GetCode(image);
            var codeForm = new CodeForm();
            codeForm.Show(image);
            //http://my.37.com/code_check.php?callback=jQuery18307459920782130212_1423155277537&save_code=3423&_=1423155370096
            request = net.SendRequest("http://my.37.com/code_check.php?callback=avc&save_code=" + codeForm.Code + "&_=" + DateTime.Now.ToFileTime(), "GET", cookies);
            var html = net.GetResponseHtmlGzip(request);
            html = html.Replace("avc(", "").Replace(")", "");
            var result = (JObject)JsonConvert.DeserializeObject(html);
            ConsoleBLL.WriteLineWaring("Check code:" + result.ToString());
            return codeForm.Code;
        }

        private bool InputLocalCode(CookieContainer cookies)
        {
            //http://gameapp.37.com/controller/code.php
            var request = net.SendRequest("http://gameapp.37.com/controller/code.php", "GET", cookies);
            var data = net.GetResponseData((HttpWebResponse)request.GetResponse(), true);
            var code = GameHelper.GetLocalCode(data);
            if (string.IsNullOrEmpty(code))
            {
                return false;
            }
            //					data:{code:code,key:"dts_entergame",action:"check_code"},
            request = net.SendRequest("http://gameapp.37.com/controller/code.php", "POST", cookies);
            net.PostData("code=" + code + "&key=dts_entergame&action=check_code", request);
            var html = net.GetResponseHtmlGzip(request);
            ConsoleBLL.WriteLineWaring("Check Code:\r\n" + html);
            var result = (JObject)JsonConvert.DeserializeObject(html);
            Thread.Sleep(500);
            if (result["code"].ToString() == "1")
            {
                return true;
            }
            else
            {
                ConsoleBLL.WriteLineError(this.player + " 验证码错误！");
            }
            return false;
        }

        private string GetLocalCode(CookieContainer cookies)
        {
            //http://gameapp.37.com/controller/code.php
            var request = net.SendRequest("http://my.37.com/code.php", "GET", cookies);
            var data = net.GetResponseData((HttpWebResponse)request.GetResponse(), true);
            return GameHelper.GetLocalCode(data);
        }

        internal Monster GetMonster(long p)
        {
            lock (monsterLocker)
            {
                return monsters.FirstOrDefault(w => w.InstanceID == p);
            }
        }

        #region 登录加密
        static string Encrypt(string pwd)
        {
            var maxPos = ch.Length - 2;
            Random random = new Random();
            random.NextDouble();
            var w = new List<string>();
            for (var i = 0; i < 15; i++)
            {
                w.Add(ch[((int)Math.Floor(random.NextDouble() * maxPos))].ToString());
                if (i == 7) { w.Add(pwd.Substring(0, 3)); }
                if (i == 12) { w.Add(pwd.Substring(3)); }
            }
            return __rsa(string.Join("", w));
        }

        static string __rsa(string str)
        {
            var len = str.Length; var i = 0; var out0 = "";
            while (i < len)
            {
                var c1 = str[i++] & 0xff;
                if (i == len) { out0 += ch[c1 >> 2]; out0 += ch[(c1 & 0x3) << 4]; out0 += "=="; break; }
                var c2 = str[i++];
                if (i == len)
                {
                    out0 += ch[c1 >> 2]; out0 += ch[((c1 & 0x3) << 4) | ((c2 & 0xF0) >> 4)]; out0 += ch[((c2 & 0xF) << 2)]; out0 += "="; break;
                }
                var c3 = str[(i++)]; out0 += ch[(c1 >> 2)]; out0 += ch[(((c1 & 0x3) << 4) | ((c2 & 0xF0) >> 4))]; out0 += ch[(((c2 & 0xF) << 2) | ((c3 & 0xC0) >> 6))];
                out0 += ch[(c3 & 0x3F)];
            }
            return out0;
        }

        static string ch = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
        #endregion
    }
}
